package com.wzdigit.wms.wms.service.order;

import com.alibaba.fastjson.JSON;
import com.wzdigit.framework.Shift;
import com.wzdigit.framework.utils.RedisUtil;
import com.wzdigit.mes.basic.api.BasicDataItemDetailApi;
import com.wzdigit.mes.basic.api.BasicSimpleCodeRuleApi;
import com.wzdigit.mes.basic.dto.DataItemDetailDTO;
import com.wzdigit.wms.basic.client.request.transfer.CreateTransferRequest;
import com.wzdigit.wms.basic.client.request.transfer.WhsReq;
import com.wzdigit.wms.basic.client.response.Result;
import com.wzdigit.wms.basic.client.response.basic.CarrierResponse;
import com.wzdigit.wms.basic.client.response.basic.VehicleResponse;
import com.wzdigit.wms.basic.client.response.basic.WarehouseApiResponse;
import com.wzdigit.wms.basic.domain.basic.Vehicle;
import com.wzdigit.wms.basic.domain.dtos.inventory.SnInforDto;
import com.wzdigit.wms.basic.domain.dtos.inventory.SnInforGoodsDto;
import com.wzdigit.wms.basic.domain.dtos.inventory.SnInforMinDto;
import com.wzdigit.wms.basic.domain.dtos.inventory.UpdateInventoryInputDto;
import com.wzdigit.wms.basic.domain.dtos.transfer.TransferDtlDto;
import com.wzdigit.wms.basic.domain.dtos.transfer.TransferDto;
import com.wzdigit.wms.basic.domain.inventory.Goods;
import com.wzdigit.wms.basic.domain.inventory.GoodsLog;
import com.wzdigit.wms.basic.domain.inventory.SimpleGoodsVersion;
import com.wzdigit.wms.basic.domain.inventory.GoodsVersion;
import com.wzdigit.wms.basic.domain.inventory.InvTrans;
import com.wzdigit.wms.basic.domain.transfer.TransferDtl;
import com.wzdigit.wms.basic.domain.transfer.TransferDtlGoods;
import com.wzdigit.wms.basic.domain.transfer.TransferHeader;
import com.wzdigit.wms.basic.enums.*;
import com.wzdigit.wms.basic.enums.operate.OperateCodeEnum;
import com.wzdigit.wms.basic.mapper.core.basic.WarehouseMapper;
import com.wzdigit.wms.basic.util.HttpSessionUtil;
import com.wzdigit.wms.common.entity.StatusCode;
import com.wzdigit.wms.wms.service.basic.CarrierService;
import com.wzdigit.wms.wms.service.basic.UserDataPermissionService;
import com.wzdigit.wms.wms.service.basic.VehicleService;
import com.wzdigit.wms.wms.service.basic.WarehouseService;
import com.wzdigit.wms.wms.service.core.GoodsService;
import com.wzdigit.wms.basic.service.code.GoodsVersionService;
import com.wzdigit.wms.basic.service.code.InventoryService;
import com.wzdigit.wms.wms.service.core.UserDataPermService;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.utils.BeanUtil;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * <p>
 * 转仓 服务类
 * </p>
 *
 * @author
 * @since 2021-01-12
 */
@Service
@Slf4j
public class TurnWarehouseService {

    @Autowired
    private WarehouseMapper warehouseMapper;

    @Autowired
    private UserDataPermissionService userDataPermissionService;

    @Autowired
    @Lazy
    private WarehouseService warehouseService;

    @Autowired
    private VehicleService vehicleService;

    @Autowired
    private GoodsService goodsService;
    
    @Autowired
    private GoodsVersionService goodsVersionService;

    @Autowired
    private UserDataPermService userDataPermService;

    @Autowired
    @Lazy
    private TransferService transferService;

    @Autowired
    @Lazy
    private InventoryService inventoryService;

    @Autowired
    private CarrierService carrierService;

    @Value("${order.code.transfer}")
    private String transferCode;

    @Value("${order_type.transfer.dictionary_code}")
    private String dictionaryCode;

    //普通调拨(一步调拨)
    @Value("${order_type.transfer.ptyb}")
    private String ptyb;

    @Value("${mycache.prefix.transfer_ware}")
    private String cachePrefix;

    @Reference(version = "${dubbo.consumers.basic.data.item.detail.api:1.0.0}", check = false)
    private BasicDataItemDetailApi basicDataItemDetailApi;

    @Reference(version = "${dubbo.consumers.basic.simple.code.rule.api:1.0.0}", check = false)
    private BasicSimpleCodeRuleApi basicSimpleCodeRuleApi;

    //仓库权限
    public static final String whs = "WHS";

    //中转仓CODE
    public static final int turnCode = WarehouseEnum.TRANSIT_WHS.code;

    //成品仓CODE
    public static final int finishingCode = WarehouseEnum.FINISHED_PRODUCT_WHS.code;

    //待上架状态
    private static final Integer WAITING_ON = 2;

    /**
     * 获取【转出仓库】下拉信息
     *
     * @param userId
     * @return 该用户拥有的仓库操作权限的仓库信息
     */
    public Result<List<WarehouseApiResponse>> getRollOutWarehouse(Integer userId) {

        //获取该用户拥有的仓库操作权限的仓库信息，
        ////过滤类型为【中转仓】的（WHS_TYPE=4）
//        List<WarehouseApiResponse> warehouseApiResponseList = getWarehouseApiResponses(userId, turnCode);
        List<WarehouseApiResponse> warehouseApiResponseList = getWarehouseApiResponses(userId, null);

        Result<List<WarehouseApiResponse>> result = new Result<>();
        result.setData(warehouseApiResponseList);
        return result;
    }

    /**
     * @param userId 用户ID
     * @param type   仓库类型
     * @return
     */
    private List<WarehouseApiResponse> getWarehouseApiResponses(Integer userId, Integer type) {
        //该用户所拥有的仓库权限数据
        List<?> whsList = userDataPermService.getPermsByUserIdAndAttr(userId, whs);
        //仓库信息集
        List<WarehouseApiResponse> responseList = new ArrayList<>();

        //修改类型
        for (Object wh : whsList) {
            WarehouseApiResponse warehouseApiResponse = (WarehouseApiResponse) wh;
            responseList.add(warehouseApiResponse);
        }

        //不过滤类型
        if (type == null) {
            return responseList;
        }

        //仓库信息
        return responseList.stream()
                .filter(s -> s.getWhsType().equals(type))
                .collect(Collectors.toList());
    }

    /**
     * 根据用户ID和仓库类型获取该用户所拥有权限下的仓库信息
     *
     * @param userId
     * @param name
     * @return
     */


    /**
     * 根据用户获取到对应权限的【目的仓库】下拉信息
     *
     * @param userId
     */
    public Result<List<WarehouseApiResponse>> getTargetWarehouse(Integer userId) {
        //获取该用户拥有的仓库操作权限的仓库信息，
        ////过滤类型为【成品仓】的（WHS_TYPE=3）
//        List<WarehouseApiResponse> warehouseApiResponseList = getWarehouseApiResponses(userId, finishingCode);
        List<WarehouseApiResponse> warehouseApiResponseList = getWarehouseApiResponses(userId, null);

        Result<List<WarehouseApiResponse>> result = new Result<>();
        result.setData(warehouseApiResponseList);
        return result;
    }

    /**
     * 获取全部【目的仓库】下拉信息
     */
    public Result<List<WarehouseApiResponse>> getTargetWarehouse() {
        //获取该用户拥有的仓库操作权限的仓库信息，
        ////过滤类型为【成品仓】的（WHS_TYPE=3）
//        List<WarehouseApiResponse> warehouseApiResponseList = getWarehouseApiResponses(userId, finishingCode);
        List<WarehouseApiResponse> warehouseApiResponseList = warehouseMapper.selectAllByStatus(new Integer(1));

        Result<List<WarehouseApiResponse>> result = new Result<>();
        result.setData(warehouseApiResponseList);
        return result;
    }


    /**
     * 根据搜索关键字查询 车辆信息
     *
     * @param selectKey
     * @return
     */
    public Result<List<Vehicle>> getVehicleInfo(String selectKey) {
        List<Vehicle> vehicleList = vehicleService.getVehicleInfo(selectKey);
//
        Result<List<Vehicle>> result = new Result<>();
        result.setData(vehicleList);
        return result;
    }

    /**
     * 根据条码，扫码方式查询 产品信息
     *
     * @param sn
     * @param twScanMode 单台0
     * @return
     */
    public Result<List<SnInforDto>> getSnInfo(String sn, Integer twScanMode, Integer whsId) {

        List<SnInforDto> snInforDtos = new ArrayList<>();

        snInforDtos = getSnInforDtoList(sn, twScanMode, whsId);
        Result<List<SnInforDto>> result = new Result<>();
        result.setData(snInforDtos);
        return result;
    }

    /**
     * 查看，并检查sn是否在SN中
     *
     * @param sn
     * @param twScanMode 单台0
     * @param whsId
     * @return
     */
    private List<SnInforDto> getSnInforDtoList(String sn, Integer twScanMode, Integer whsId) {

        int waitUpCode = GoodsStatusEnum.WAIT_UP.getCode();//待上架--2
        int hasUpCode = GoodsStatusEnum.HAS_UP.getCode();//已上架--3
        int hasDownCode = GoodsStatusEnum.HAS_DOWN.getCode();//已下架--5
        int waitDowmCode = GoodsStatusEnum.WAIT_DOWM.getCode();//已下架--4


        List<SnInforDto> snInforDtos;
        if (twScanMode.equals(0)) {
            //单台
            snInforDtos = goodsService.selectSnInfosBySn(sn, SnScanTypeEnum.SELECT_SN);
        } else {
            //整板
            snInforDtos = goodsService.selectSnInfosBySn(sn, SnScanTypeEnum.SELECT_PALLET);
        }

        //过滤仓库为转出仓
        snInforDtos = snInforDtos.stream().filter(s -> s.getWhsId() != null).filter(s -> s.getWhsId().equals(whsId)).collect(Collectors.toList());

        if (snInforDtos.size() == 0) {
            String msg = String.format("该条码:%s未在所选转出仓查询到相关信息", sn);
            Shift.fatal(msg);
        }

        for (SnInforDto snInforDto : snInforDtos) {

            if ((!(snInforDto.getStatus().equals(waitUpCode))) && (!(snInforDto.getStatus().equals(waitDowmCode)))) {
                GoodsStatusEnum statusEnum = GoodsStatusEnum.getEnumByCode(snInforDto.getStatus());
                String enumName = statusEnum.getEnumName();

                String msg = String.format("转仓要求SN为[待上架]或[已下架]状态，当前SN[%s]为【%s】状态", snInforDto.getGoodsSn(), enumName);
                Shift.fatal(msg);
            }
        }
        return snInforDtos;
    }

    /**
     * 创建转仓单
     */
    @Deprecated
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void createTransfer() {


        //删除用户缓存
        RedisUtil.delete("");

    }

    /**
     * 将缓存到前端页面的数据写入Redis缓存
     *
     * @param createTransferRequest
     * @return
     */
    public Result backAndInsert(CreateTransferRequest createTransferRequest) {

        log.info("写缓存:{}", createTransferRequest);

        //用户ID
        Integer userId = createTransferRequest.getUserId();

        //写入Redis缓存，其key值为userID
        String cacheKey = cachePrefix + userId;
        log.info("key:{}", cacheKey);

        boolean flag = RedisUtil.set(cacheKey, createTransferRequest);
        log.info("写入结果:{}", flag);

        Result result = new Result();
        result.setFlag(flag);
        return result;
    }

    /**
     * 根据用户ID获取缓存信息
     *
     * @param userId
     * @return
     */
    public Result<CreateTransferRequest> getTurnCache(Integer userId) {

        String cacheKey = cachePrefix + userId;
        log.info("查询缓存，key:{}", cacheKey);

        Object cache = RedisUtil.get(cacheKey);

        CreateTransferRequest createTransferRequest = null;
        if (cache != null) {
            createTransferRequest = (CreateTransferRequest) cache;
        }

        Result<CreateTransferRequest> result = new Result<>();
        result.setData(createTransferRequest);
        return result;
    }

    /**
     * TODO 后续调整代码风格
     * 创建转仓单
     * 步骤：
     * 1）校验SNInfoListAll是否存在，并且可转仓。调【SN是否存在检验】服务
     * 2）根据车辆信息ID的运输公司(CARRIER_ID)，获取承运人信息信息(WMS_CARRIER)，调 查询【承运人信息】服务
     * 3）获取转仓单号，调单据编码的服务：单据编码服务(现有生成单据方法)
     * 4）调创建转收货单服务：调【生成调拨单】服务
     * 5）调【库存更新】服务，更新库位库存表，源仓库【预支数量】增加，目的仓库【预售数量】增加。调【生成库存日志】服务
     * 调【更新货品】服务，变更产品SN状态。调【生成SN操作日志】服务
     *
     * @param createTransferRequest
     * @throws Exception 
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
//    public Result<TransferDto> createTransferRequest(CreateTransferRequest createTransferRequest, HttpServletRequest servletRequest) {
    public Result<String> createTransferRequest(CreateTransferRequest createTransferRequest, HttpServletRequest servletRequest) throws Exception {
    	//产品条码明细
        List<SnInforDto> snInforDtoList = createTransferRequest.getSnInforDtoList();
    	//SN集合
    	List<String> snList = snInforDtoList.stream().map(SnInforDto::getGoodsSn).distinct().collect(Collectors.toList());
    	List<SimpleGoodsVersion> simpleGoodsVersionList = goodsVersionService.selectSimpleBySnList(snList);
    	Map<String, Integer> simpleGoodsVersionMap = simpleGoodsVersionList.stream().collect(Collectors.toMap(SimpleGoodsVersion::getGoodsSn, SimpleGoodsVersion::getVersion));
    	
        int waitUpCode = GoodsStatusEnum.WAIT_UP.getCode();//待上架--2
        int hasUpCode = GoodsStatusEnum.HAS_UP.getCode();//已上架--3
        int hasDownCode = GoodsStatusEnum.HAS_DOWN.getCode();//已拣选--5
        int waitDowmCode = GoodsStatusEnum.WAIT_DOWM.getCode();//已下架--4

        //当前时间
        Date localDate = new Date();
        //登录人
        String loginName = HttpSessionUtil.getLoginName(servletRequest);
//        String loginName = "gxm";

        //转出仓库
        WhsReq turnWhsReq = createTransferRequest.getTurnWhsReq();
        //目的仓库
        WhsReq targetWhsReq = createTransferRequest.getTargetWhsReq();

        //先校验SN是否存在，SN是否在转成仓中--------------------start
        for (String sn : snList) {
            boolean flag = goodsService.checkExist(sn);
            if (!flag) {
                String msg = String.format("SN:%s不存在！", sn);
                Shift.fatal(StatusCode.BUSINESS_ERR, msg);
            }

            //检查SN是否在所选仓库中----------------start
            String whsName = turnWhsReq.getWhsName();
            //根据转出仓库ID和SN码查询
            Goods goods = goodsService.selectByGoodsSnAndWhsId(turnWhsReq.getWhsId(), sn);
            if (goods == null) {
                String msg = String.format("SN:%s，在仓库:【%s】中未找到！", sn, whsName);
                Shift.fatal(StatusCode.BUSINESS_ERR, msg);
            }

            Goods goods1 = goodsService.selectBySn(sn);
//            if (!goods1.getStatus().equals(waitUpCode)) {
//            if ((!(goods1.getStatus().equals(waitUpCode))) && (!(goods1.getStatus().equals(hasUpCode))) && (!(goods1.getStatus().equals(hasDownCode)))) {
            if ((!(goods1.getStatus().equals(waitUpCode))) && (!(goods1.getStatus().equals(waitDowmCode)))) {

                GoodsStatusEnum statusEnum = GoodsStatusEnum.getEnumByCode(goods1.getStatus());
                String enumName = statusEnum.getEnumName();

                String msg = String.format("条码:%s状态为【%s】，录入失败！", goods1.getGoodsSn(), enumName);
                Shift.fatal(StatusCode.BUSINESS_ERR, msg);
            }

            //检查SN是否在所选仓库中----------------end

        }
        //先校验SN是否存在，SN是否在转成仓中--------------------end


        //获取承运信息
        Vehicle vehicle = createTransferRequest.getVehicle();
        Integer carrierId = vehicle.getCarrierId();
        Integer vehicleId = vehicle.getVehicleId();
        //承运信息
        VehicleResponse vehicleResponse = vehicleService.getVehicle(vehicleId);
        CarrierResponse carrier = carrierService.getCarrier(carrierId);

        //获取转仓单号
        //即调拨单号
        String transferNo = basicSimpleCodeRuleApi.GenerateCode(transferCode);


        //调【生成调拨单】服务
        TransferDto transferDto = new TransferDto();

        //根据数据字典获取调拨单类型
        List<DataItemDetailDTO> dataItemDetailDTOList = basicDataItemDetailApi.getDataItemDetailByCode(dictionaryCode);
        List<DataItemDetailDTO> dataItemDetailDTOS = dataItemDetailDTOList.stream().filter(s -> s.getItemName().equals(ptyb)).collect(Collectors.toList());
        DataItemDetailDTO dataItemDetailDTO = dataItemDetailDTOS.get(0);
        //调拨单类型
        String transferType = dataItemDetailDTO.getItemValue();

        //单头
        TransferHeader transferHeader = new TransferHeader();
        transferHeader.setTransferNo(transferNo);
        transferHeader.setTransferType(transferType);//调拨单类型
        transferHeader.setFmWhs(turnWhsReq.getWhsId());//来源仓库
        transferHeader.setToWhs(targetWhsReq.getWhsId());//目的仓库
        transferHeader.setDeliveryVehicleNo(vehicleResponse.getVehicleNo());//车牌号
        transferHeader.setDeliveryVehicleType(vehicleResponse.getVehicleType());//车型
        transferHeader.setDriver(vehicleResponse.getDriver());//司机
        transferHeader.setFmBusinessMan(loginName);//来源方业务员

        transferHeader.setTransferCreateTime(localDate);//调拨单创建时间
        transferHeader.setStatus(TransferHeaderStatusEnum.CREATE.getCode());
        transferHeader.setCreateTime(localDate);
        transferHeader.setCreateUser(loginName);

        //明细 SnInforGoodsDto
        List<SnInforMinDto> snInforMinDtoList = new ArrayList<>();
        for (SnInforDto snInforDto : snInforDtoList) {

            SnInforMinDto snInforMinDto = new SnInforMinDto();
            BeanUtil.copyNonNull(snInforDto, snInforMinDto);
            //查询货品表
            Goods goods = goodsService.selectByGoodsId(snInforDto.getGoodsId());

            //更新GOODS
            //清空PKG_ID
            //后面调整的需求，那干脆写这吧
            if (snInforDto.getTwScanMode().equals(0)) {
                log.info("单台清空PKG_ID");
                Goods goodsUpdate = new Goods();
                goodsUpdate.setGoodsId(goods.getGoodsId());
                goodsUpdate.setModifyUser(loginName);
                goodsUpdate.setModifyTime(new Date());
                Integer row = goodsService.updateGoodsDePackage(goodsUpdate);
                log.info("成功更新{}条记录", row);
            }
            //清空PKG_ID


            SnInforGoodsDto snInforGoodsDto = new SnInforGoodsDto();
            BeanUtil.copyNonNull(goods, snInforGoodsDto);

            snInforMinDto.setSnInforGoodsDto(snInforGoodsDto);
            snInforMinDto.setUnit(goods.getUnit());
            snInforMinDto.setVendorId(goods.getVendorId());

            snInforMinDtoList.add(snInforMinDto);
        }

        //将明细分组
        Map<SnInforGoodsDto, List<SnInforMinDto>> dtoListMap = snInforMinDtoList.stream().collect(Collectors.groupingBy(SnInforMinDto::getSnInforGoodsDto));
//        Map<Integer, List<SnInforMinDto>> dtoListMap = snInforMinDtoList.stream().collect(Collectors.groupingBy(SnInforMinDto::getSkuId));

        //调拨单明细集合
        List<TransferDtlDto> transferDtlDtoList = new ArrayList<>();

        //TRANSFER_LINE_NO
        Integer lineNo = 1;
        for (Map.Entry<SnInforGoodsDto, List<SnInforMinDto>> entry : dtoListMap.entrySet()) {
//        for (Map.Entry<Integer, List<SnInforMinDto>> entry : dtoListMap.entrySet()) {


            TransferDtlDto transferDtlDto = new TransferDtlDto();

            List<SnInforMinDto> inforMinDtoList = entry.getValue();

            //数量
            BigDecimal countBD = inforMinDtoList.stream().map(s -> s.getQty()).reduce(BigDecimal.ZERO, BigDecimal::add);


            //调拨单明细

            TransferDtl transferDtl = new TransferDtl();
            SnInforMinDto snInforMinDto = inforMinDtoList.get(0);
            SnInforGoodsDto snInforGoodsDto = snInforMinDto.getSnInforGoodsDto();

            transferDtl.setTransferNo(transferNo);
            transferDtl.setFmSku(snInforGoodsDto.getSkuId());
            transferDtl.setFmOwner(snInforGoodsDto.getOwner());
            transferDtl.setFmFactory(snInforGoodsDto.getFactory());
            transferDtl.setFmVendor(snInforGoodsDto.getVendorId());
            transferDtl.setFmInvAttr(snInforGoodsDto.getInvAttr());
            transferDtl.setFmQaStatus(snInforGoodsDto.getQaStatus());
            transferDtl.setFmLotno(snInforGoodsDto.getLotno());
            transferDtl.setUdf1(snInforGoodsDto.getPoNo());//采购订单

            //目标与来源一致
            transferDtl.setToSku(snInforGoodsDto.getSkuId());
            transferDtl.setToOwner(snInforGoodsDto.getOwner());
            transferDtl.setToQaStatus(snInforGoodsDto.getQaStatus());
            transferDtl.setToFactory(snInforGoodsDto.getFactory());
            transferDtl.setToLotno(snInforGoodsDto.getLotno());


            transferDtl.setUnit(snInforMinDto.getUnit());//TODO 单位????????????????
            transferDtl.setOrderQty(countBD.intValue());//TODO 调拨数量
            transferDtl.setTransitQty(0).setCmpQty(0);//在途数量和完成数量


            transferDtl.setStatus(TransferDtlStatusEnum.CREATE.getCode());//新建
            transferDtl.setCreateTime(localDate);
            transferDtl.setCreateUser(loginName);
            transferDtl.setTransferLineNo(lineNo.toString());
            lineNo = lineNo + 1;
            transferDtl.setFmVendor(snInforMinDto.getVendorId());


            //设置PO,SO,SO_LINE
            Goods goods = goodsService.selectBySn(snInforGoodsDto.getGoodsSn());

            transferDtl.setFmPo(goods.getPoNo());//来源订单号
            transferDtl.setToPo(goods.getPoNo());//目标订单号
            transferDtl.setFmSoNo(goods.getSoNo());
            transferDtl.setToSoNo(goods.getSoNo());
            transferDtl.setFmSoLineNo(goods.getSoItem());
            transferDtl.setToSoLineNo(goods.getSoItem());


            //设置【调拨单明细】
            transferDtlDto.setTransferDtl(transferDtl);


            //调拨单单货品清单集合
            List<TransferDtlGoods> transferDtlGoodsList = new ArrayList<>();
            for (SnInforMinDto inforMinDto : inforMinDtoList) {
                TransferDtlGoods transferDtlGoods = new TransferDtlGoods();

                SnInforGoodsDto goodsDto = inforMinDto.getSnInforGoodsDto();
                BeanUtil.copyNonNull(goodsDto, transferDtlGoods);
                transferDtlGoods.setStatus(TransferDtlGoodStatusEnum.WAIT_RECEIVE.getCode());//todo 待接收

                transferDtlGoods.setCreateTime(localDate);
                transferDtlGoods.setCreateUser(loginName);

                transferDtlGoodsList.add(transferDtlGoods);
            }

            //设置【调拨单单货品清单集合】
            transferDtlDto.setTransferDtlGoods(transferDtlGoodsList);

            transferDtlDtoList.add(transferDtlDto);
        }
        //调拨单单货品清单
        //创建调拨单
        transferDto.setTransferHeader(transferHeader).setTransferDtlDtoList(transferDtlDtoList);
        //调创建调拨单方法
        transferService.addNewOne(transferDto);
        //调创建调拨单服务---------------------------------END


        //调【库存更新】服务，更新库位库存表，源仓库【预支数量】增加，目的仓库【预售数量】增加。调【生成库存日志】服务-----start

        ////转出仓库
        //WhsReq turnWhsReq = createTransferRequest.getTurnWhsReq();
        //目的仓库
        //WhsReq targetWhsReq = createTransferRequest.getTargetWhsReq();

        //更新库存：中转仓和成品仓，更新俩记录
        //更新后写日志，俩日志
        changeInventory(localDate, loginName, turnWhsReq, targetWhsReq, transferNo, transferDto, transferType, transferDtlDtoList, false);
//        int a = 0 / 0;

        //添加日志事务
        //调【库存更新】服务，更新库位库存表，源仓库【预支数量】增加，目的仓库【预售数量】增加。调【生成库存日志】服务-----end

        //调【更新货品】服务，变更产品SN状态。调【生成SN操作日志】服务 start

        for (TransferDtlDto dtlDto : transferDtlDtoList) {
            List<TransferDtlGoods> transferDtlGoods = dtlDto.getTransferDtlGoods();
            for (TransferDtlGoods dtlGood : transferDtlGoods) {
                GoodsVersion goods = goodsVersionService.selectById(dtlGood.getGoodsId());
                goods.setVersion(simpleGoodsVersionMap.get(goods.getGoodsSn()));	// 条码数据版本
                
                String oldJson = JSON.toJSONString(goods);	//原先的json
                
                goods.setStatus(10);			// 转出在途
                goods.setModifyTime(localDate);
                goods.setModifyUser(loginName);
                goodsVersionService.updateById(goods);
                
                String newJson = JSON.toJSONString(goods);	//更新后的json

                //生成SN操作日志
                GoodsLog goodsLog = new GoodsLog();
                goodsLog.setCreateTime(localDate);
                goodsLog.setCreateUser(loginName);
                goodsLog.setGoodsSn(goods.getGoodsSn());
                goodsLog.setOpCode(OpCodeEnum.TRANSFEROUT.getCode());
                goodsLog.setOperator(loginName);
                goodsLog.setUpdateContent("未更新的:" + oldJson + ",更新的:" + newJson);
                goodsService.insertGoodsLog(goodsLog);
            }
        }

        //调【更新货品】服务，变更产品SN状态。调【生成SN操作日志】服务 end


        //提交完成后删除缓存
        Integer userId = createTransferRequest.getUserId();
        log.info("用户ID{}", userId);

        //是否有缓存
        String cacheKey = cachePrefix + userId;
        log.info("缓存Key:{}", cacheKey);
        boolean flag = RedisUtil.hasKey(cacheKey);
        log.info("是否有缓存:{}", flag);

        //有则删除
        if (flag) {
            RedisUtil.delete(cacheKey);
        }
        Result<String> result = new Result<>();
        result.setData(transferNo);
        return result;
    }


    /**
     * 更新库存
     * 调【库存更新】服务，更新库位库存表，源仓库【预支数量】增加，目的仓库【预售数量】增加。调【生成库存日志】服务
     *
     * @param localDate          当前时间
     * @param loginName          登录人
     * @param turnWhsReq         源仓
     * @param targetWhsReq       目的仓
     * @param transferNo         调拨单号
     * @param transferDto        调拨单单头与明细
     * @param transferType       调拨单类型
     * @param transferDtlDtoList 调拨单明细
     * @param flag               标识是否为更换【目的仓】,flag = true
     * @throws Exception 
     */
    public void changeInventory(Date localDate,
                                String loginName,
                                WhsReq turnWhsReq,
                                WhsReq targetWhsReq,
                                String transferNo,
                                TransferDto transferDto,
                                String transferType,
                                List<TransferDtlDto> transferDtlDtoList,
                                boolean flag) throws Exception {
        Integer orderNo = 1;
        for (TransferDtlDto transferDtlDto : transferDtlDtoList) {
            //源仓
            //中转仓
            TransferDtl sourceTransferDtl = transferDtlDto.getTransferDtl();

            //设置源仓信息
            UpdateInventoryInputDto source = setSourceLocInventory(loginName, turnWhsReq, transferDto, sourceTransferDtl);
            log.info("source:{}", source.toString());

            if (flag) {
                source.setPreOutQty(null);//todo 预支数量
                source.setPreInQty(new BigDecimal(sourceTransferDtl.getOrderQty() * (-1)));//todo 预收数量
            }


            //更新完中转仓后写日志
            //记录库存事务日志
            InvTrans sourceInvTrans = getInvTrans(localDate, loginName, turnWhsReq, transferNo, transferType, orderNo, source);


            //目的仓
            UpdateInventoryInputDto target = setTargetLocInventory(loginName, targetWhsReq, sourceTransferDtl);
            log.info("target:{}", target.toString());

            orderNo++;

            UpdateInventoryInputDto fmInv = new UpdateInventoryInputDto();
            BeanUtil.copyNonNull(source, fmInv);
            if (flag) {
                //flag =true ,表示更新【目的仓】,将【预支数量】设置为0
                fmInv.setPreOutQty(new BigDecimal(0));
            }

            UpdateInventoryInputDto toInv = new UpdateInventoryInputDto();
            BeanUtil.copyNonNull(target, toInv);
            log.info("fmInv:" + fmInv.toString());
            log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            log.info("toInv:" + toInv.toString());
            log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            log.info("sourceInvTrans:" + sourceInvTrans.toString());
            log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

            inventoryService.inventoryTransfer(fmInv, toInv, sourceInvTrans);
            log.info("fmInv:{}", fmInv.toString());
            log.info("toInv:{}", toInv.toString());
        }
    }

    /**
     * 设置目的仓信息
     *
     * @param loginName
     * @param targetWhsReq
     * @param sourceTransferDtl
     * @return
     */
    private UpdateInventoryInputDto setTargetLocInventory(String loginName, WhsReq targetWhsReq, TransferDtl sourceTransferDtl) {
        BigDecimal zero = BigDecimal.ZERO;

        UpdateInventoryInputDto target = new UpdateInventoryInputDto();
        target.setOperator(loginName);
        target.setWhsId(targetWhsReq.getWhsId());

        target.setOwner(sourceTransferDtl.getToOwner());//货主ID
        target.setSkuId(sourceTransferDtl.getToSku());//物料ID
        target.setFactory(sourceTransferDtl.getToFactory());//工厂
        target.setVendorId(sourceTransferDtl.getToVendor());//供应商ID
        target.setLotNo(sourceTransferDtl.getToLotno());//内部批次号
        target.setInvAttr(sourceTransferDtl.getToInvAttr());//TODO 库存性质
        target.setQaStatus(sourceTransferDtl.getToQaStatus());//品质状态
        target.setQty(zero);//数量
        target.setUnit(sourceTransferDtl.getUnit());//单位
        target.setPreInQty(new BigDecimal(sourceTransferDtl.getOrderQty()));//todo 预收数量
        target.setPreOutQty(zero);//todo 预支数量

        target.setHoldQty(zero);//TODO 冻结
        target.setPreAlocQty(zero);//TODO 预配数量
        target.setAlocQty(zero);//TODO 分配数量
        target.setLotNo(sourceTransferDtl.getToLotno());
        target.setOperator(loginName);
        return target;
    }

    /**
     * 设置源仓信息
     *
     * @param loginName
     * @param turnWhsReq
     * @param transferDto
     * @param sourceTransferDtl
     * @return
     */
    private UpdateInventoryInputDto setSourceLocInventory(String loginName, WhsReq turnWhsReq, TransferDto transferDto, TransferDtl sourceTransferDtl) {
        BigDecimal zero = BigDecimal.ZERO;

        UpdateInventoryInputDto source = new UpdateInventoryInputDto();


        source.setOperator(loginName);
        source.setWhsId(turnWhsReq.getWhsId());

        source.setOwner(sourceTransferDtl.getFmOwner());//货主ID
        source.setSkuId(sourceTransferDtl.getFmSku());//物料ID
        source.setFactory(sourceTransferDtl.getFmFactory());//工厂
        source.setVendorId(sourceTransferDtl.getFmVendor());//供应商ID
        source.setLotNo(sourceTransferDtl.getFmLotno());//内部批次号
        source.setInvAttr(sourceTransferDtl.getFmInvAttr());//TODO 库存性质
        source.setQaStatus(sourceTransferDtl.getFmQaStatus());//品质状态
        source.setQty(zero);//TODO 数量
        source.setUnit(sourceTransferDtl.getUnit());//单位
        source.setPreOutQty(new BigDecimal(sourceTransferDtl.getOrderQty()));//todo 预支数量
        source.setPreInQty(zero);//todo 预收数量

        source.setHoldQty(zero);//TODO 冻结数量
        source.setPreAlocQty(zero);//TODO 预分配数量
        source.setAlocQty(zero);//TODO 分配数量
        source.setOperator(loginName);
        source.setVendorId(transferDto.getTransferDtlDtoList().get(0).getTransferDtl().getFmVendor());//供应商ID
        return source;
    }


    /**
     * 设置【库存事务日志】
     *
     * @param localDate
     * @param loginName
     * @param turnWhsReq
     * @param transferNo
     * @param transferType
     * @param orderNo
     * @param source
     * @return
     */
    private InvTrans getInvTrans(Date localDate, String loginName, WhsReq turnWhsReq, String transferNo, String transferType, Integer orderNo, UpdateInventoryInputDto source) {
        InvTrans sourceInvTrans = new InvTrans();
        sourceInvTrans.setCreateTime(localDate);
        sourceInvTrans.setCreateUser(loginName);

        //todo 下面的数据很有问题
        sourceInvTrans.setOpCode(OperateCodeEnum.CREATE.getEnumName());//TODO 操作
        sourceInvTrans.setDocType(transferType);//单据类型
        sourceInvTrans.setDocNo(transferNo);//TODO 单据号==调拨单号？？
        sourceInvTrans.setStatus(InvTransStatusEnum.FINISHED.getCode()); //TODO 0 未完成，暂时写死 交易状态
        sourceInvTrans.setTransTime(localDate);//TODO 交易时间
        sourceInvTrans.setOperator(loginName);
        sourceInvTrans.setFmOwner(source.getOwner());//TODO 货主
        sourceInvTrans.setFmSkuId(source.getSkuId());
//        sourceInvTrans.setFmLocId(source.getLocId());
        sourceInvTrans.setToWhsId(source.getWhsId());
        sourceInvTrans.setFmUnit(source.getUnit());
        sourceInvTrans.setFmQty(source.getQty());
        sourceInvTrans.setToOwner(source.getOwner());
        sourceInvTrans.setToSkuId(source.getSkuId());
        sourceInvTrans.setToWhsId(source.getWhsId());
        sourceInvTrans.setToUnit(source.getUnit());
        sourceInvTrans.setToQty(source.getQty());

        sourceInvTrans.setDocLineNo(orderNo.toString());//TODO 单据行号
        sourceInvTrans.setFmWhsId(turnWhsReq.getWhsId());//TODO 库存地点
        return sourceInvTrans;
    }


    /**
     * 修改目的仓，更新库存,【仅仅用于变更目的仓，将目的仓送回源仓】
     *
     * @param localDate
     * @param loginName
     * @param turnWhsReq
     * @param targetWhsReq
     * @param transferNo
     * @param transferDto
     * @param transferType
     * @param transferDtlDtoList
     * @param flag
     * @throws Exception 
     */
    public void changeInventory2(Date localDate,
                                 String loginName,
                                 WhsReq turnWhsReq,
                                 WhsReq targetWhsReq,
                                 String transferNo,
                                 TransferDto transferDto,
                                 String transferType,
                                 List<TransferDtlDto> transferDtlDtoList,
                                 boolean flag) throws Exception {
        Integer orderNo = 1;
        for (TransferDtlDto transferDtlDto : transferDtlDtoList) {
            //源仓
            //中转仓
            TransferDtl sourceTransferDtl = transferDtlDto.getTransferDtl();

            //设置源仓信息
            UpdateInventoryInputDto source = setSourceLocInventory(loginName, turnWhsReq, transferDto, sourceTransferDtl);
            if (flag) {
                source.setPreOutQty(null);//todo 预支数量
                source.setPreInQty(new BigDecimal(sourceTransferDtl.getOrderQty() * (-1)));//todo 预收数量
            }


            //更新完中转仓后写日志
            //记录库存事务日志
            InvTrans sourceInvTrans = getInvTrans(localDate, loginName, turnWhsReq, transferNo, transferType, orderNo, source);


            //目的仓
            UpdateInventoryInputDto target = setTargetLocInventory(loginName, targetWhsReq, sourceTransferDtl);
            if (flag) {
                target.setPreOutQty(new BigDecimal(sourceTransferDtl.getOrderQty() * (-1)));//todo 预支数量
                target.setPreInQty(null);//预收数量
            }

            orderNo++;

            UpdateInventoryInputDto fmInv = new UpdateInventoryInputDto();
            BeanUtil.copyNonNull(source, fmInv);
//            if (flag) {
//                //flag =true ,表示更新【目的仓】,将【预支数量】设置为0
//                fmInv.setPreOutQty(new BigDecimal(0));
//            }

            UpdateInventoryInputDto toInv = new UpdateInventoryInputDto();
            BeanUtil.copyNonNull(target, toInv);
            log.info("fmInv:" + fmInv.toString());
            log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            log.info("toInv:" + toInv.toString());
            log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            log.info("sourceInvTrans:" + sourceInvTrans.toString());
            log.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

            inventoryService.inventoryTransfer(fmInv, toInv, sourceInvTrans);
        }
    }
}
